/**
 |------------------------------------------------------------------|
 |                  __.--'\     \.__./     /'--.__                  |
 |              _.-'       '.__.'    '.__.'       '-._              |
 |            .'                SAM API               '.            |
 |           /               Source code                \           |
 |          |          Copyright(C) 2015, linling        |          |
 |          |             All rights reserved.           |          |
 |           \         .---.              .---.         /           |
 |            '._    .'     '.''.    .''.'     '.    _.'            |
 |               '-./            \  /            \.-'               |
 |                                ''                                |
 |------------------------------------------------------------------|
 * 	
 */
#include <string.h>
#include <stdint.h>
#include "xos2.h"
#include "api.h"
#include "xThread_rtx5.h"

xThread::xThread(osPriority_t priority, uint32_t stack_size, unsigned char *stack_mem, const char *name){
    memset(&_obj_mem, 0, sizeof(_obj_mem));
    memset(&_attr, 0, sizeof(_attr));
    _attr.priority = priority;
    _attr.stack_size = stack_size;
    _attr.name = name ? name : "application_unnamed_thread";
    _attr.stack_mem = (uint32_t*)stack_mem;
    _attr.cb_size = sizeof(_obj_mem);
    _attr.cb_mem = &_obj_mem;
}

void xThread::start(void(*task) (void *), void * arg){
    if (_attr.stack_mem == NULL){
        _attr.stack_mem = new uint32_t[_attr.stack_size / sizeof(uint32_t)];
    }
    //Fill the stack with a magic word for maximum usage checking
    //for (uint32_t i = 0; i < (_attr.stack_size / sizeof(uint32_t)); i++){
    //    ((uint32_t *)_attr.stack_mem)[i] = 0xE25A2EA5;
    //}

    osThreadNew(task, arg, &_attr);
}
xThreadBase::xThreadBase(int priority, unsigned int stack_size, unsigned char* stack_mem, const char* name) {
    id = new xThread((osPriority_t)priority, stack_size, stack_mem, name);
}
void xThreadBase::start(void(*task) (void*), void* arg) {
    xThread* t = (xThread*)id;
    t->start(task, arg);
}
void xos::Pass(void){
    osThreadYield();
}

void xos::Wait(int ms){
    osDelay(ms);
}

unsigned int xos::TickGet(void) {
    return (unsigned int)osKernelGetTickCount();
}

uint32 xos_TickGet(){
    return (unsigned int)osKernelGetTickCount();
}

int xos::ThreadGetId(void){
   return  (int)osThreadGetId();
}

const char* xos::ThreadGetName(int tid){
    const char* name = osThreadGetName((osThreadId_t)tid);
    if(name == NULL){	  
        return "rtx5";
    }
    return name;
}
void xos::KernelSuspend(void){
    osKernelSuspend();
}

void xos::ThreadTerminate(int tid){
    osThreadTerminate((osThreadId_t)tid);
}

void xos::EmptyFn(void){}

void xos::PrintStack(void){
    uint32_t thread_n;
    osThreadId_t *threads;
    uint32_t stack_size_sum = 0;
    uint32_t space_size_sum = 0;
    uint32_t use_size = 0;
    uint32_t use_rate = 0;

    thread_n = osThreadGetCount();
    threads = new osThreadId_t[thread_n];

    //osKernelLock();
    thread_n = osThreadEnumerate(threads, thread_n);

    osPrintf("------------- all thread stack use rate ----------\n");
    osPrintf("  task name  |  size  |   use  |  space | userate |\n");
    osPrintf("--------------------------------------------------\n");
    for (int i = 0; i < thread_n; i++){
        uint32_t stack_size = osThreadGetStackSize(threads[i]);
        uint32_t space_size = osThreadGetStackSpace(threads[i]);
        use_size = stack_size - space_size;
        use_rate = use_size * 1000 / stack_size;
        stack_size_sum += stack_size;
        space_size_sum += space_size;
        osPrintf(" %-12.12s|%8l|%8l|%8l|%6L.%L%%|\n", 
            osThreadGetName(threads[i]), 
            stack_size, 
            use_size, 
            space_size, 
            use_rate / 10, use_rate mod 10);
    }
    osPrintf("--------------------------------------------------\n");
    use_size = stack_size_sum - space_size_sum;
    use_rate = use_size * 1000 / stack_size_sum;
    osPrintf(" %-12.12s|%+8l|%+8l|%+8l|%6L.%L%%|\n", 
        "", 
        stack_size_sum, 
        use_size, 
        space_size_sum, 
        use_rate / 10, use_rate mod 10);
    //osKernelUnlock();
    delete[] threads;
}





unsigned int xSignal::Wait_And(unsigned int wait_flags){
    return osThreadFlagsWait(wait_flags, osFlagsWaitAll, osWaitForever);
}
unsigned int xSignal::Wait_Or(unsigned int wait_flags){
    return osThreadFlagsWait(wait_flags, osFlagsWaitAny, osWaitForever);
}
unsigned int xSignal::Wait_And(unsigned int wait_flags, unsigned int timeout){
    return osThreadFlagsWait(wait_flags, osFlagsWaitAll, timeout);
}
unsigned int xSignal::Wait_Or(unsigned int wait_flags, unsigned int timeout){
    return osThreadFlagsWait(wait_flags, osFlagsWaitAny, timeout);
}
void xSignal::Set(unsigned int event_flags, unsigned int task_id){
    osThreadFlagsSet((osThreadId_t)task_id, event_flags);
}
void xSignal::IsrSet(unsigned int event_flags, unsigned int task_id){
    osThreadFlagsSet((osThreadId_t)task_id, event_flags);
}
void xSignal::Clr(unsigned int clear_flags){
    osThreadFlagsClear(clear_flags);
}
unsigned int xSignal::Read(void){
    return osThreadFlagsGet();
}


xMutex::xMutex(){
    osMutexAttr_t             _attr;
    memset(mut, 0, sizeof(mut));
    memset(&_attr, 0, sizeof(_attr));
    _attr.name = "xMutex";
    _attr.cb_mem = mut;
    _attr.cb_size = sizeof(mut);
    _attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
    osMutexNew(&_attr);
}
void xMutex::Wait(void){
    osMutexAcquire((osMutexId_t)mut, osWaitForever);
}
void xMutex::Release(void){
    osMutexRelease((osMutexId_t)mut);
}
void xMutex::Lock(void){
    osMutexAcquire((osMutexId_t)mut, osWaitForever);
}
void xMutex::UnLock(void){
    osMutexRelease((osMutexId_t)mut);
}
void xMutex::lock(void){
    osMutexAcquire((osMutexId_t)mut, osWaitForever);
}
void xMutex::unlock(void){
    osMutexRelease((osMutexId_t)mut);
}
void xosMutex_Init(void* mut){
	int obj_size = 4*8;
	osMutexAttr_t             _attr;
	memset(mut, 0, obj_size);
	memset(&_attr, 0, sizeof(_attr));
	_attr.name = "xosMutex";
	_attr.cb_mem = mut;
	_attr.cb_size = obj_size;
	_attr.attr_bits = osMutexRecursive | osMutexPrioInherit | osMutexRobust;
	osMutexNew(&_attr);
}
void xosMutex_Wait(void* mut){
	osMutexAcquire((osMutexId_t)mut, osWaitForever);
}
void xosMutex_Release(void* mut){
	osMutexRelease((osMutexId_t)mut);
}

xSemaphore::xSemaphore() {
	xSemaphore_Init(sem, 0);
}
xSemaphore::xSemaphore(unsigned int token_count) {
	xSemaphore_Init(sem, token_count);
}
void xSemaphore::Wait(void) {
	osSemaphoreAcquire((osSemaphoreId_t)sem, osWaitForever);
}
int xSemaphore::Wait(unsigned int timeout) {
	int r = osSemaphoreAcquire((osSemaphoreId_t)sem, timeout);
	return (r == osErrorTimeout) ? -1: r;
}
void xSemaphore::Release(void) {
	osSemaphoreRelease((osSemaphoreId_t)sem);
}

void xSemaphore_Init(void* sem, unsigned int token_count) {
	int obj_size = 4 * 4;
	osSemaphoreAttr_t             _attr;
	memset(sem, 0, obj_size);
	memset(&_attr, 0, sizeof(_attr));
	_attr.name = "xSemaphore";
	_attr.cb_mem = sem;
	_attr.cb_size = obj_size;
	_attr.attr_bits = 0;
	osSemaphoreNew((token_count == 0) ? 1 : token_count, token_count, &_attr);
}
void xSemaphore_Wait(void* sem) {
	osSemaphoreAcquire((osSemaphoreId_t)sem, osWaitForever);
}
int xSemaphore_Wait_Timeout(void* sem, unsigned int timeout) {
	int r = osSemaphoreAcquire((osSemaphoreId_t)sem, timeout);
	return (r == osErrorTimeout) ? -1: r;
}
void xSemaphore_Release(void* sem) {
	osSemaphoreRelease((osSemaphoreId_t)sem);
}
void xSemaphore_ReleaseIsr(void* sem){
	osSemaphoreRelease((osSemaphoreId_t)sem);
}

xEvent::xEvent() {
    init();
}
void xEvent::init(void) {
    osEventFlagsAttr_t attr;
	memset(&attr, 0, sizeof(attr));
	memset(evt, 0, sizeof(osRtxEventFlags_t));
    attr.name = "xEvent";
    attr.cb_mem = evt;
    attr.cb_size = sizeof(osRtxEventFlags_t);
    osEventFlagsNew(&attr);
}
unsigned int xEvent::set(unsigned int flags) {
    return osEventFlagsSet((osEventFlagsId_t)evt, flags);
}
unsigned int xEvent::set_isr(unsigned int flags) {
    return set(flags);
}
unsigned int xEvent::clear(unsigned int flags) {
    return osEventFlagsClear((osEventFlagsId_t)evt, flags);
}
unsigned int xEvent::get() {
    return osEventFlagsGet((osEventFlagsId_t)evt);
}
unsigned int xEvent::wait_all(unsigned int flags, unsigned int millisec, bool clear) {
    return osEventFlagsWait((osEventFlagsId_t)evt, flags, osFlagsWaitAll | ((!clear) ? osFlagsNoClear : 0), millisec);
}
unsigned int xEvent::wait_any(unsigned int flags, unsigned int millisec, bool clear) {
    return osEventFlagsWait((osEventFlagsId_t)evt, flags, osFlagsWaitAny | ((!clear) ? osFlagsNoClear : 0), millisec);
}


/*
extern "C" {
    extern void xosStart(void* task, void* tbuff, int tsize); 
}
osRtxThread_t _main_obj;

void xosStart(void* task, void* tbuff, int tsize){
    osThreadAttr_t _main_thread_attr;

    _main_thread_attr.stack_mem = tbuff;
    _main_thread_attr.stack_size = tsize;
    _main_thread_attr.cb_size = sizeof(_main_obj);
    _main_thread_attr.cb_mem = &_main_obj;
    _main_thread_attr.priority = osPriorityNormal;
    _main_thread_attr.name = "main_thread";
    osThreadId_t result = osThreadNew((osThreadFunc_t)task, NULL, &_main_thread_attr);
    //if ((void *)result == NULL){
    //    error("Pre main thread not created");
    //}
    osKernelStart();
}
*/
